import { getUid } from 'ol/util'
import { boundingExtent } from 'ol/extent'
import { fromExtent } from 'ol/geom/Polygon'
import VectorSource from 'ol/source/Vector'
import { Fill, Icon, Stroke, Style, Text } from 'ol/style'
import * as turf from '@turf/turf'
import { OlCluster, OlFeature, OlVectorLayer } from './type'
import { getMarkerClusterDefaultStyle } from './defaultOptions'
import { isFunction, debounce } from './utils'
import img0 from './images/m0.png'
import img1 from './images/m1.png'
import img2 from './images/m2.png'
import img3 from './images/m3.png'
const defaultOptions = {
	zIndex: 3, // 覆盖物的叠加顺序
	noClusterZoom: 18, // 在zoom及以上不聚合
	distance: 40, // 要素将聚集在一起的距离（以像素为单位）
	minDistance: 30, //  簇之间的最小距离（以像素为单位）
	showViewExtent: true, // 只展示可视区域 Marker
	zoomOnClick: true, // 是否点击展开 Cluster
	averageCenter: false, // 聚合点的图标位置是否是所有聚合内点的中心点。默认为否
	styles: [] // 自定义1-10 ,11-100,101-1000,10001- 聚合物的样式
}
// marker Text样式处理
function createSingleTextStyle(style) {
	return {
		placement: style.placement, // 默认为point
		text: style.label,
		offsetX: style.labelXOffset,
		offsetY: style.labelYOffset,
		fill: new Fill({
			// 字体颜色
			color: style.fontColor
		}),
		font: `${style.fontWeight} ${style.fontSize} ${style.fontFamily}`, // 字体样式
		backgroundFill: new Fill({
			// 背景颜色
			color: style.labelBgColor
		}),
		backgroundStroke: new Stroke({
			// 边框样式
			color: style.borderColor,
			width: 10,
			lineCap: 'round', // 线帽风格  butt, round, 或者 square 默认 round
			lineJoin: 'round', // 线连接方式 bevel, round, 或者 miter 默认 round
			lineDash: [], // 线间隔模式 控制虚线
			lineDashOffset: 0, // 线段间隔偏移 默认0
			miterLimit: 10 // 默认10
		}),
		padding: style.padding,
		textBaseline: style.textBaseline, // 似乎无效
		textAlign: style.textAlign //文本对齐方式,似乎无效
	}
}
function createSingleIconStyle(style) {
	const sIconStyle = {
		crossOrigin: 'anonymous', // 图片跨域允许
		anchor: [0.5, 0.5], // 原点位置
		anchorOrigin: 'top-left', // 原点位置偏移方向
		anchorXUnits: 'fraction', // 基于原点位置百分比
		anchorYUnits: 'fraction', // 基于原点位置像素
		offset: [0, 0], // 偏移量设置，相对于原点
		scale: 1, // 图标缩放比例
		opacity: 1, // 透明度
		src: style.icon,
		// img: style.img, // 图标的url
		rotateWithView: style.rotateWithView, // 是否旋转
		rotation: style.rotation // 旋转角度
	}
	return sIconStyle
}
// 设置聚合物不同数量的自定义样式
const getClusterStyle = (img, size, defaultStyle, style = {}) => {
	const { url, offset, angle, textColor, textSize, textWeight } = style
	const iconStyle = createSingleIconStyle({
		icon: url || img,
		offset: offset || [0, 0],
		angle: angle || defaultStyle.angle,
		rotateWithView: defaultStyle.rotateWithView
	})
	const textStyle = createSingleTextStyle({
		label: size.toString() || defaultStyle.label,
		font: defaultStyle.font,
		fontSize: textSize || defaultStyle.fontSize,
		fontFamily: defaultStyle.fontFamily,
		fontWeight: textWeight || defaultStyle.fontWeight,
		fontColor: textColor || defaultStyle.fontColor,
		labelXOffset: defaultStyle.labelXOffset,
		labelYOffset: defaultStyle.labelYOffset,
		labelBgColor: defaultStyle.labelBgColor,
		borderColor: defaultStyle.borderColor,
		borderWidth: defaultStyle.borderWidth,
		padding: defaultStyle.padding,
		placement: defaultStyle.placement,
		textBaseline: defaultStyle.textBaseline,
		textAlign: defaultStyle.textAlign
	})
	return {
		textStyle,
		iconStyle
	}
}
// 设置聚合要素样式
function createClusterStyle(styleCache, defaultStyle, assignOptions, feature) {
	const size = feature.get('features').length // 获取该要素所在聚合群的要素数量
	let style = styleCache[size]
	const styles = assignOptions.styles || []
	// styles
	if (!style) {
		let clusterStyle = {
			textStyle: {},
			iconStyle: {}
		}
		if (size == 1) {
			// 处理 VMarker 和 正常 Marker
			const marker = feature.get('features')[0]
			return !marker.get('VMarker') ? marker.getStyle() : null
		} else if (size < 11) {
			clusterStyle = getClusterStyle(img0, size, defaultStyle, styles[0])
		} else if (size < 101) {
			clusterStyle = getClusterStyle(img1, size, defaultStyle, styles[1])
		} else if (size < 1001) {
			clusterStyle = getClusterStyle(img2, size, defaultStyle, styles[2])
		} else {
			clusterStyle = getClusterStyle(img3, size, defaultStyle, styles[3])
		}
		style = [
			new Style({
				image: new Icon(clusterStyle.iconStyle),
				text: new Text(clusterStyle.textStyle),
				zIndex: defaultStyle.zIndex // 设置层级
			})
		]
		styleCache[size] = style
	}
	return style
}
// Cluster change 单个 marker 添加
const addOverlaysAction = (map, clusterSource, features, showViewExtent) => {
	//获取可视区域范围的1.2倍
	const mapsize = map.getSize().map(it_ => it_ * 1.2)
	const extent = map.getView().calculateExtent(mapsize)
	//获取可视区域范围的几何对象
	const viewGeometry = fromExtent(extent)
	features.forEach(feature => {
		const markers = feature.get('features')
		const showZoomFeature = feature.get('showZoomFeature')
		if (!markers) {
			//不存在 features 即为 单个  VMarker
			const VMarker = feature.get('VMarker')
			if (VMarker) {
				// 获取 VMarker id
				const id = VMarker.getId()
				// 获取 VMarker 经纬度
				const coordinate = VMarker.getPosition()
				// 判断是否在可视区域内
				const inViewGeometry = viewGeometry.intersectsCoordinate(coordinate)
				// 判断是否已经添加
				const inOverlaysList = clusterSource.overlayIds.includes(id)
				if (!inOverlaysList) {
					// 未被添加的 VMarker
					if (inViewGeometry && showViewExtent) {
						//只添加在可视区域
						clusterSource.overlayIds.push(id)
						map.add(VMarker)
					}
					if (!showViewExtent) {
						// 可视区域外的也添加
						clusterSource.overlayIds.push(id)
						map.add(VMarker)
					}
				}
			} else {
				// 获取  id
				const id = feature.getId()
				// 获取 feature 经纬度
				const position = feature.get('position')
				const coordinate = [position.olng, position.olat]
				// 判断是否在可视区域内
				const inViewGeometry = viewGeometry.intersectsCoordinate(coordinate)
				// 判断是否已经添加
				const inOverlaysList = clusterSource.showZoomFeatureIds.includes(id)
				clusterSource.singleFeatureIds.add(id)
				if (!inOverlaysList) {
					// 未被添加
					if (inViewGeometry && showViewExtent) {
						//只添加在可视区域
						clusterSource.showZoomFeatureIds.push(id)
						map.add(feature)
					}
					if (!showViewExtent) {
						// 可视区域外的也添加
						clusterSource.showZoomFeatureIds.push(id)
						map.add(feature)
					}
				}
			}
		} else if (showZoomFeature) {
			//处理zoom 不聚合情况
			feature.setGeometry(null) // 清空聚合图形
			addOverlaysAction(map, clusterSource, markers, showViewExtent)
		}
	})
}
//创建要素聚合数据来源
function createClusterSource(map, vectorSource, options) {
	const { distance, minDistance, showViewExtent, noClusterZoom, averageCenter } = options
	// 创建要素聚合数据来源
	const clusterSource = new OlCluster({
		distance: parseInt(distance, 10),
		minDistance: parseInt(minDistance, 10),
		source: vectorSource,
		createCluster(point, features) {
			let cluster = null
			const zoom = map.getZoom()
			const showZoomFeature = zoom >= noClusterZoom
			if (features.length == 1) {
				const VMarker = features[0].get('VMarker')
				clusterSource.singleFeatureIds.add(features[0].getId())
				// 创建聚合对象时候，只有一个聚合物情况
				cluster = VMarker
					? new OlFeature({
            VMarker
					  })
					: new OlFeature({
							geometry: point,
							features,
							// 聚合下一个要素，其唯一子 feature 已经注册监听事件，传递 WEvents，在 WMap dispatchAction
							WEvents: features[0].get('WEvents')
					  })
			} else {
				if (averageCenter) {
					const turfFeatures = features.map(feature => {
						return turf.point(feature.getGeometry().getCoordinates())
					})
					const featureCollection = turf.featureCollection(turfFeatures)
					const centerCoordinates = turf.center(featureCollection).geometry.coordinates
					point.setCoordinates(centerCoordinates)
				}
				cluster = new OlFeature({
					geometry: point,
					features,
					showZoomFeature
				})
				cluster.setId(getUid(cluster))
			}
			cluster.WTYPE = 'ClusterMarker'
			return cluster
		}
	})
	// 拖动变化-主动触发 clusterSource  change
	// 拖动时，判断Feature是否有变化，可优化
	map.on('moveend', e => clusterSource.changed(e))
	const clusterSourceChangeCallback = function (e) {
		const features = e.target.getFeatures()
		// 添加前先清除所有 VMarker
		clusterSource.overlayIds.forEach(id => {
			const VMarker = map.getOverlayById(id)
			map.remove(VMarker)
		})
		clusterSource.showZoomFeatureIds.forEach(id => {
			const feature = map.getFeatureById(id)
			map.remove(feature)
		})
		clusterSource.overlayIds = []
		clusterSource.showZoomFeatureIds = []
		if (features.length > 0) {
			// 添加每个聚合物相应的 OverlayMarker
			addOverlaysAction(map, clusterSource, features, showViewExtent)
		}
	}
	/**
	 * 监听聚合物体变化 ，用于清除聚合状态下 自定义overlays数量
	 * 	addFeatures/removeFeature 也会触发
	 */
	clusterSource.on(
		'change',
		debounce(e => {
			clusterSourceChangeCallback(e)
		}, 200)
	)
	return clusterSource
}

/**
 * 创建聚合物覆盖群
 * @param {object} map
 * @param {object} options distance = 40, minDistance = 30
 * @param {object} features
 * @returns
 */
function createMarkerCluster(map, markers, options) {
	const styleCache = {}
	const assignOptions = Object.assign({}, defaultOptions, options)
	const features = markers.map(marker => {
		// 聚合对象单个矢量要素需要重新注册
		return marker.olTarget
	})
	// 创建要素数据来源
	const vectorSource = new VectorSource({
		features
	})
	// 创建要素聚合数据来源
	const clusterSource = createClusterSource(map, vectorSource, assignOptions)
	const defaultStyle = getMarkerClusterDefaultStyle()
	// 创建一个图层
	const clusterLayer = new OlVectorLayer({
		className: 'WMap-clusterer-layer',
		source: clusterSource,
		zIndex: 1,
		style: feature => createClusterStyle(styleCache, defaultStyle, assignOptions, feature)
	})
	// 默认添加图层
	map.addLayer(clusterLayer) // 初始默认数据添加图层
	return { clusterLayer, assignOptions }
}

function WMarkerCluster(map, features = [], options) {
	if (!map || map.WTYPE !== 'MAP') throw new Error('WMarkerCluster warn: 请传入正确的map对象~')
	const events = ['click', 'dblclick', 'contextmenu'] // 支持的事件
	const { clusterLayer, assignOptions } = createMarkerCluster(map, features, options) // 聚合图层
	this.olTarget = clusterLayer // 聚合图层
	this.options = assignOptions
	this.map = map
	this.WTYPE = 'MARKERCLUSTER'
	this.WEvents = new Map() // 存储事件
	this.getView = () => this.map.getView() // 获取地图的初始化 View 信息
	this.getMaxZoom = () => this.getView().getMaxZoom() // 获取地图设置的最大放大
	this.getVectorSource = () => this.olTarget.getSource().getSource() //  Marker集合数据对象
	this.getClusterSource = () => this.olTarget.getSource() //  聚合物集合数据对象
	this.getDistance = () => this.getClusterSource().getDistance() // 聚合的距离
	this.setDistance = distance => this.olTarget.getSource().setDistance(distance)
	this.getMinDistance = () => this.olTarget.getSource().getMinDistance() // 聚合物的最小间距
	this.setMinDistance = minDistance => this.olTarget.getSource().setMinDistance(minDistance)
	this.hasFeature = feature => this.getVectorSource().hasFeature(feature) // 矢量要素是否在聚合图层上
	this.getId = function () {
		return getUid(this.olTarget)
	}
	// 获取聚合类的所有基础Marker集合
	this.getMarkers = () => {
		return this.getVectorSource().getFeatures()
	}
	// 将Marker集合添加到聚合
	this.setMarkers = features => {
		const distance = this.getDistance()
		const minDistance = this.getMinDistance()
		if (Array.isArray(features) && features.length > 0) {
			this.olTarget && this.map.removeLayer(this.olTarget)
			const { clusterLayer, assignOptions } = createMarkerCluster(this.map, features, {
				distance,
				minDistance
			})
			this.options = assignOptions
			this.olTarget = clusterLayer
			return this.olTarget
		}
	}
	// 添加Marker
	this.add = (...args) => {
		if (args.length === 1) {
			if (Array.isArray(args[0])) {
				this.add(...args[0])
			} else if (args[0].WTYPE === 'OVERLAYMARKER' || args[0].WTYPE === 'FEATUREMARKER') {
				const olTarget = args[0].olTarget ? args[0].olTarget : args[0]
				this.getVectorSource().addFeature(olTarget)
			}
		} else {
			const markers = args.map(marker => {
				if (marker.WTYPE === 'OVERLAYMARKER' || marker.WTYPE === 'FEATUREMARKER') {
					return marker.olTarget
				}
			})
			this.getVectorSource().addFeatures(markers)
		}
	}
	// 删除Marker
	this.remove = (...args) => {
		if (args.length === 1) {
			// 单参数或者数组
			if (Array.isArray(args[0])) {
				this.remove(...args[0])
			} else if (args[0].WTYPE === 'FEATUREMARKER' || args[0].WTYPE === 'OVERLAYMARKER') {
				// removeFeature 时候 触发 change 事件，并且会 remove VMarker
				const olTarget = args[0].olTarget ? args[0].olTarget : args[0]
				console.log(this.hasFeature(olTarget))
				this.getVectorSource().removeFeature(olTarget)
			}
		} else {
			// 多个参数
			args.forEach(marker => this.remove(marker))
		}
	}
	// 清空 Markers
	this.clearMarkers = () => {
		// 遍历清空已经渲染 OverlayMarkers
		this.getClusterSource().overlayIds.forEach(id => {
			const VMarker = this.map.getOverlayById(id)
			this.map.remove(VMarker)
		})
		this.getClusterSource().overlayIds = [] // 清空overlayMarkers 数据
		this.getClusterSource().showZoomFeatureIds = [] // 清空 showZoomFeature
		this.getVectorSource().clear() // 清空 Marker集合数据对象
	}
	// 点击散开属性
	this.setZoomOnClick = function (zoomOnClick = false) {
		this.options.zoomOnClick = zoomOnClick
	}
	/* 聚合物放大展开，视野适应地图
	 *@param{object}  target  聚合features 对象
	 *@param{Array}  	options  组成聚合物的 feature 集合
	 *@return {object} target
	 *@存在问题，会使 zoom 出现小数
	 */
	this.setClusterExtentView = function (target, options = {}) {
		// 所有要素坐标集合
		if (!target || target.WTYPE !== 'ClusterMarker') return
		const features = target.get('features')
		const coordinates = features.length > 1 ? features.map(r => r.getGeometry().getCoordinates()) : features.getGeometry().getCoordinates()
		// 放大地图，让要素刚好出现在视野
		this.getView().fit(boundingExtent(coordinates), {
			maxZoom: this.getMaxZoom(),
			duration: 300,
			padding: [100, 100, 100, 100], // 点要素距离视野边距
			nearest: true,
			...options
		})
		return target
	}
	//事件监听
	this.on = (eventName, callBack = () => {}) => {
		if (callBack && !isFunction(callBack)) throw new Error('请传入正确的 callBack!')
		if (!eventName || typeof eventName !== 'string') throw new Error('请传入正确的 eventName！')
		const WEventName = !events.includes(eventName) ? eventName : 'WCluster(' + eventName + ')' + this.getId()
		const eventObject = {
			eventName: WEventName,
			callBack,
			handler: e => {
				e.callBack({
					type: e.eventName,
					target: this,
					event: e.event,
					eventTarget: e.eventTarget
				})
			}
		}
		// 未绑定过事件
		if (!this.WEvents.has(eventObject.eventName)) {
			//事件监听-  传递如：WMarkerCluster(cliclk)
			this.olTarget.on(eventObject.eventName, eventObject.handler)
			//储存事件
			this.WEvents.set(eventObject.eventName, eventObject)
		} else {
			const currentEventObject = this.WEvents.get(eventObject.eventName)
			// 移除事件
			this.olTarget.un(currentEventObject.eventName, currentEventObject.handler)
			// 重新设置监听事件
			this.olTarget.on(currentEventObject.eventName, eventObject.handler)
			//储存新事件
			this.WEvents.set(currentEventObject.eventName, eventObject)
		}
		//设置 WEvents
		this.olTarget.set('WEvents', this.WEvents)
	}
	//事件移除
	this.off = eventName => {
		eventName = 'WCluster(' + eventName + ')' + this.getId()
		if (this.WEvents.has(eventName)) {
			// 获取事件对象
			const currentEventObject = this.WEvents.get(eventName)
			// 移除事件
			this.olTarget.un(currentEventObject.eventName, currentEventObject.handler)
			// 删除事件存储
			this.WEvents.delete(eventName)
			this.olTarget.set('WEvents', this.WEvents)
			callBack()
		}
	}
	map.setMarkerClusterer(this) // map 上添加 markerCluster
}

export default WMarkerCluster
